// ContentIOPlugin.cpp : Defines the exported functions for the DLL application.
//

#include "stdafx.h"
#include "ContentIOPlugin.h"
#include "..\Shared\ObjectManager.h"
#include <iostream>
#include <fstream>

__declspec(dllexport) IPlugin* __stdcall CreateInstance()
{
	return (IPlugin*)new ContentIOPlugin();
}

__declspec(dllexport) int __stdcall GetInterfaceVersion(void)
{
	return PluginInterfaceVersion;
}

ContentIOPlugin::ContentIOPlugin()
{
	m_ModuleInfo.pluginName = "ContentIOPlugin";
	m_ModuleInfo.author = "Chun Lin";
	m_ModuleInfo.version = 0x00000001; // 0xMMmmaabb   MM = Major mm = Minor aa = Macro bb = Build
	m_ModuleInfo.numOfCommands = 3;
	m_ModuleInfo.commands[0] = "SaveObject";
	m_ModuleInfo.commands[1] = "LoadObject";
	m_ModuleInfo.commands[2] = "ItemFactory";
}

bool __stdcall ContentIOPlugin::HandleCommand(Command &NewCommand)
{
	if(NewCommand.name == "SaveObject")
	{
		SaveObject(NewCommand.Arguments[0].ToCharPtr(), NewCommand.Arguments[2].ToCharPtr(), NewCommand.Arguments[1].ToCharPtr());
		return true;
	}
	else if(NewCommand.name == "LoadObject")
	{
		LoadObject(NewCommand.Arguments[0].ToCharPtr());
		return true;
	}
	else if(NewCommand.name == "ItemFactory")
	{
		ItemFactory(NewCommand);
	}
	return false;
}

void ContentIOPlugin::SaveObject(std::string FileName, const std::string FileMode, const std::string ObjectName, int Tabs)
{
	FileIO *FilePointer = new FileIO;
	int NumberOfAttributes=0;

	Object &TestObject = (*m_Objects)[ObjectName.c_str()];
	NumberOfAttributes = m_Objects->GetNumberOfAttributesFromObject(TestObject.GetBaseAttribute("Name")); 

	if(!Tabs)
		FilePointer ->WriteFile(FileName, Value("Dummy","Value"), FileMode, ObjectName);

	for(int i = 0; i < NumberOfAttributes; ++i)
	{
		/*for(int j = 0; j < Tabs; ++j)
			std::cout << "\t";*/
		Value TempValue = TestObject.GetBaseAttribute(i);
		
		if(strcmp(TempValue.name, "Head") == 0 || strcmp(TempValue.name, "RHand") == 0 || strcmp(TempValue.name, "LHand") == 0 || strcmp(TempValue.name, "Feet") == 0 || strcmp(TempValue.name, "Chest") == 0)
		{
			TempValue = (*m_Objects)[TempValue].GetBaseAttribute("Name");
			//std::cout << TempValue.ToSendableString() << std::endl;
			FilePointer ->WriteFile(FileName, TempValue, "File App", ObjectName, Tabs);
		}
		else
		{
			//std::cout << TestObject.GetBaseAttribute(i).ToSendableString() << std::endl;
			FilePointer ->WriteFile(FileName, TestObject.GetBaseAttribute(i), "File App", ObjectName, Tabs);
		}
	}
	FilePointer ->WriteFile(FileName, Value("New","Line"), "File App", ObjectName, Tabs+1);
	//std::cout << std::endl;
	int NumberOfChildren = m_Objects->GetNumberOfChildrenFromObject(TestObject.GetBaseAttribute("Name"));
	for(int i = 0; i < NumberOfChildren; ++i)
	{
		SaveObject(FileName, "File App", TestObject[i].GetBaseAttribute("Name").ToCharPtr(), Tabs+1);
	}

	delete FilePointer;
}

void ContentIOPlugin::LoadObject(std::string FileName)
{
	FileIO *FilePointer = new FileIO;
	FilePointer->OpenFile(FileName);

	std::string CurrentLine = "\t";
	int CurrentIndex;
	int FirstIndex = -1;
	ObjectManager &r_ObjectManager = *m_Objects;
	while(CurrentLine != "")
	{
		CurrentLine = FilePointer->ReadFile();
		if(CurrentLine != "")
		{
			//std::cout << CurrentLine << std::endl;
			int Pos = CurrentLine.find_last_of('\t');
			if(CurrentLine.find_last_of('\t') != std::string::npos)
			{
				CurrentLine = CurrentLine.substr(CurrentLine.find_last_of('\t')+1);
				if(CurrentLine == "")
				{
					CurrentLine = "1";
					continue;
				}
			}
			Value NewValue;
			NewValue.SetFromSendable((char *)CurrentLine.c_str());
			if(strcmp(NewValue.name, "Name") == 0)
			{
				if(!r_ObjectManager.AddObject())
					return;
				CurrentIndex = r_ObjectManager.GetSize()-1;
				if(FirstIndex == -1)
					FirstIndex = CurrentIndex;
				else
					r_ObjectManager.AddChildToObject(FirstIndex, CurrentIndex);
				r_ObjectManager[CurrentIndex].GetBaseAttribute("Name") = NewValue;
			}
			else if(strcmp(NewValue.name, "X") == 0 || strcmp(NewValue.name, "Y") == 0 || strcmp(NewValue.name, "ImageIndex") == 0)
			{
				r_ObjectManager[CurrentIndex].GetBaseAttribute(NewValue.name) = NewValue;
			}
			else
			{
				r_ObjectManager.AddAttributeToObject(CurrentIndex, NewValue);
			}
		}
	}
	
	FilePointer->CloseFile();
	delete FilePointer;

	if(FirstIndex != -1)
	{
		Object &FirstObject = r_ObjectManager[FirstIndex];
		Object &Equipped = FirstObject["Equipped"];
		if(Equipped.GetBaseAttribute("Name") == "Error")
			return;
		const char* Buffer[] = {"Head","RHand","LHand","Feet","Chest"};
		for(int i = 0; i < 5; i++)
		{
			Value &Temp = Equipped.GetBaseAttribute(Buffer[i]);
			Object &EquippedItem = FirstObject[Temp];
			if(EquippedItem.GetBaseAttribute("Name") == "Error")
				Temp = -1;
			else
				Temp = EquippedItem.GetIndex();
		}
	}
}

bool ContentIOPlugin::CheckValid(Command &NewCommand, int numberOfArguments)
{
	if(NewCommand.Arguments.Size() != numberOfArguments)
	{
		return false;
	}

	return true;
}

FileIO::FileIO()
{
	WritePtr = new std::ofstream();
	LoadPtr = new std::ifstream();
	OverWriteCount = 0;
}

void FileIO::WriteFile(std::string fname, const Value & s, const std::string fmode, const std::string objname, int Tabs)
{
	if (fmode == "File App")
	{
		WritePtr ->open(fname.c_str(), std::ios::app);
	}

	else if (fmode == "File OverWrite")
	{
		WritePtr ->open(fname.c_str());
	}

	else if(fmode == "File Replace")
	{
	}
	if(!(strcmp(s.name,"Dummy") == 0 && s.GetType() == AT_STRING && s == "Value") &&
	   !(strcmp(s.name,"New") == 0 && s.GetType() == AT_STRING && s == "Line"))
	{
		for(int i = 0; i < Tabs; i++)
			*WritePtr << "\t";
		*WritePtr << s.ToSendableString() << std::endl;
	}
	else if (strcmp(s.name,"New") == 0 && s.GetType() == AT_STRING && s == "Line")
	{
		for(int i = 0; i < Tabs; i++)
			*WritePtr << "\t";
		*WritePtr << std::endl;
	}
	WritePtr->close();
}


//OpenFile calls ReadFile when file(NewCommand.Arugument[0]) is open successfully.
void FileIO::OpenFile(std::string fname)
{
	if(!LoadPtr || LoadPtr->is_open())
		return;
	bool OpenFileCheckExitLoop = false;
	std::string FailLoadYesOrNo = "";
	/*while (!OpenFileCheckExitLoop)
	{*/
		LoadPtr -> open(fname.c_str());
			
		if (LoadPtr-> rdstate() != 0)
		{
			//std::cout<<"Open file "<<fname<<"failed!"<<std::endl;
			//std::cout<<"Do you want to reload: "<<std::endl;
			//std::cin>>FailLoadYesOrNo;
			//	if ((FailLoadYesOrNo == "N")||(FailLoadYesOrNo =="n"))
			//		OpenFileCheckExitLoop = true; //Quit Opening
			//std::cin.clear();
			//std::cin.ignore();
			//
		}
		else
		{
			//std::cout << "\nFile successfully opened.\n" << std::endl;
			OpenFileCheckExitLoop = true;
			//ReadFile();	//ReadFile function call
		}
				
		
	//}
}

std::string FileIO::ReadFile()
{
	if(!LoadPtr || !LoadPtr->is_open())
		return "File Not Open";
	std::string CurrentLine;
	std::getline(*LoadPtr, CurrentLine);
	return CurrentLine;
}

FileIO::~FileIO()
{
	CloseFile();
	delete WritePtr;
	delete LoadPtr;
}
void FileIO::CloseFile()
{
	if (WritePtr != NULL)
		WritePtr->close();
	if (LoadPtr != NULL)
		LoadPtr->close();
}

//Arguments[0] Item Arguments[1] Owner Arguments[2] x Arguments[3] y
void ContentIOPlugin::ItemFactory(Command &NewCommand)
{
	Object &ItemTemplates =(*m_Objects)["ItemTemplates"];
	Object &ItemTemplate = ItemTemplates[NewCommand.Arguments[0]];
	if(ItemTemplate.GetBaseAttribute("Name") == "Error")
	{
		NewCommand.Returns.Add(Value("Error","Item does not exist as an template."));
		return;
	}
	
	m_Objects->AddObject();
	Object &NewItem = (*m_Objects)[m_Objects->GetSize()-1];
	NewItem = ItemTemplate;
	m_Objects->AddChildToObject(NewCommand.Arguments[1], NewItem.GetIndex());
	NewItem.GetBaseAttribute("X") = NewCommand.Arguments[2];
	NewItem.GetBaseAttribute("Y") = NewCommand.Arguments[3];
	NewCommand.Returns.Add(Value("Results", "Succes."));
	//Object &TestObject = (*m_Objects)[m_Objects->GetSize()-1];
	////Object &TestObject2 = (m_ObjectManager)[m_ObjectManager.GetSize()-1];
	////std::cout << itemname.ToSendableString() << " " << ownerindex.ToCharPtr() << " " << x << " " << y << std::endl;
	//std::cout << "TestObject.GetBaseAttribute(0).ToCharPtr " << TestObject.GetBaseAttribute(0).ToCharPtr() << std::endl;
	//std::cout << "TestObject.GetBaseAttribute(0).ToSendableString " << TestObject.GetBaseAttribute(0).ToSendableString() << std::endl;
	////std::cout << "TestObject2.GetBaseAttribute(0).ToCharPtr " << TestObject2.GetBaseAttribute(0).ToCharPtr() << std::endl;
	////std::cout << "TestObject2.GetBaseAttribute(0).ToSendableString " << TestObject2.GetBaseAttribute(0).ToSendableString() << std::endl;
	//std::cout << itemname.ToCharPtr() << std::endl;

	//if (TestObject.GetBaseAttribute(0).ToCharPtr() == itemname.ToCharPtr())
	//{

	//	//std::cout << itemname.ToCharPtr() << std::endl;
	//	//Object &NewObject = TestObject;
	//	//m_ObjectManager.AddChildToObject(NewObject.GetBaseAttribute(0).ToCharPtr(), ownerindex.ToCharPtr());
	//	std::cout << "it matches" << std::endl;
	
	//std::cout << "TestObject.GetBaseAttribute(0).ToCharPtr " << TestObject.GetBaseAttribute(0).ToCharPtr() << std::endl;
	//std::cout << "TestObject.GetBaseAttribute(0).ToSendableString " << TestObject.GetBaseAttribute(0).ToSendableString() << std::endl;
}